﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ChainAnalises.Classes.DivizionToAccords;
using ChainAnalises.Classes.DivizionToAccords.AuxiliaryClasses;
using ChainAnalises.Classes.DivizionToAccords.Criteria;
using ChainAnalises.Classes.IntervalAnalysis;

namespace Segmentator.Dividers
{
    /// <summary>
    /// Класс сегментации знаковой последовательности 
    /// в котором слово попадает в словарь только в том случае если фактическая и расчетная характеристики
    /// вхождений испытуемого псевдослова дают разность меньшую определенного порога. 
    /// Теория на 56 странице "Алгоритмы анализа структуры сигналов и данных"
    /// </summary>
    class OrlovDivider
    {
        private readonly Chain chain_for_divizion; // цепочка для сегментирования
        public Chain convoluted_chain; // Цепь после первой сегментации
        private readonly double balance_factor;   // Баланс между частотой и интервалами
        private readonly int start_length; // Начальная длина слова

        private LinkUp interval_link;   // Флаг привязки начала сегментации

        private Method calc_frecuncy_method; // Перечисление, определяющеме метод подсчета частот 

        /*модификации:
            1 - подсчёт интервалов с привязкой:
         *         - к началу
         *         - к концу
         *         - к обоим
         *  2 - подсчёт частот:
         *         - созвучие является элементом длиной 1
         *         - элементы созвучия считаются как отдельные элементы
         */
        public OrlovDivider(Chain chain, double balance_factor, int start_length, LinkUp interval_link, Method calc_frecuncy_method)
        {
            chain_for_divizion = chain;
            this.balance_factor = balance_factor;
            this.start_length = start_length;
            this.interval_link = interval_link;
            this.calc_frecuncy_method = calc_frecuncy_method;
        }

        public AlphabetChain alphabet = new AlphabetChain();




        public AlphabetChain DivideChain(double level)
        {
            convoluted_chain = chain_for_divizion; // исходная цепь принимается как просегментированая
            
            StdCalculator calc;
            ChainConvolutor convolutor = new ChainConvolutor();
            DictionaryEntry? entry;
            for (int l = start_length; l > 1; l--) //цикл перебирающий длины "окошка"
            {
                bool flag = true;
                while (flag)
                {
                    calc = new StdCalculator(calc_frecuncy_method, interval_link, balance_factor);
                    entry = calc.CalcStds(convoluted_chain, l, alphabet, (float) level);
                    flag = entry != null;
                    if (flag)
                    {
                       alphabet.Add((Chain)((DictionaryEntry)entry).Key);
                       convoluted_chain = convolutor.Convolute(convoluted_chain, (Chain)((DictionaryEntry)entry).Key, (IDataForStd)((DictionaryEntry)entry).Value);
                    }
                }
            }

            //оставшиеся символы загоняем в alphabet
                for (int i = 0; i < convoluted_chain.Length; i++)
                {
                    //не работает проверка наличия в алфавите этих цепей
                    if (!((convoluted_chain[i]) is Chain))
                    {
                        Chain temp = new Chain(1);
                        temp[0] = convoluted_chain[i];
                        if (!alphabet.Contains(temp))
                        {
                            alphabet.Add(temp);
                            convoluted_chain = convolutor.Convolute(convoluted_chain, temp);
                        }
                    }
                }
                return alphabet;
            
        }

        public AlphabetChain GetAlphabet()
        {
            return alphabet;
        }

        public Chain GetConvolutedChain()
        {
            return convoluted_chain;
        }
    }


    }

